#include"fftimer.h"
#include"queue/ffvframequeue.h"
#include"decoder/ffvdecoder.h"
#include"queue/ffeventqueue.h"
#include"player/ffplayercontext.h"
#include"opengl/ffglrenderwidget.h"

FFTimer::FFTimer()
    :m_stop(false),seekFlag(false),pauseFlag(false),speedFlag(false),speed(1.0f),speedFactor(1.0f)
{

}

void FFTimer::init(FFVDecoder *vDecoder_, FFVFrameQueue *frmQueue_, FFVRender *vRender_, FFGLRenderWidget *renderWidget_)
{
    vDecoder = vDecoder_;
    frmQueue = frmQueue_;
    vRender = vRender_;

    playerCtx = new FFPlayerContext();
    playerCtx->vRender = vRender_;
    playerCtx->vFrmQueue = frmQueue_;
    renderWidget = renderWidget_;
}


void FFTimer::start() {
    m_stop = false;
    setTimerInterval(1e5);
    timerTread = std::thread(&FFTimer::work,this);
}

void FFTimer::wait()
{
    if (timerTread.joinable()){
        timerTread.join();
        std::cerr<<"timer thread has joined!"<<std::endl;
    }

}

void FFTimer::stop() {
    m_stop = true;
    pauseFlag = false;
    cond.notify_all();
    pauseCond.notify_all();
}


void FFTimer::pause()
{
    bool flag = pauseFlag.load(std::memory_order_acquire);
    pauseFlag.store(!flag,std::memory_order_release);
    if(flag) {
        pauseCond.notify_one();
    }
}


void FFTimer::close()
{
    seekFlag = false;
    pauseFlag = false;
    speedFlag = false;
    speed = 1.0f;
    speedFactor = 1.0f;
}

void FFTimer::wakeAllThread()
{
    pauseCond.notify_all();
    cond.notify_all();
}

void FFTimer::setSpeed(float speed_)
{
    speedFlag.store(true,std::memory_order_release);
    speed = speed_;
}


void FFTimer::setTimerInterval(std::chrono::milliseconds interval_)
{
    interval = interval_;
}

void FFTimer::setTimerInterval(double interval_)
{
    interval = std::chrono::microseconds(static_cast<int64_t>(interval_));
}

void FFTimer::setTimerInterval(int64_t interval_)
{
    this->interval = std::chrono::microseconds(interval_);
}

void FFTimer::playVideo()
{
    //    std::cout<<"playVideo callBack run!" << std::endl;

    AVFrame* frame = frmQueue->dequeue();
    if (frame == nullptr){
        stop();
        return;
    }
    //    std::cout << "get video frame !" << std::endl;

    if(pauseFlag.load()){
        std::unique_lock<std::mutex>lock(pauseMutex);
        pauseCond.wait(lock);
        pauseFlag.store(false,std::memory_order_release);
    }

    if(!frame->data[0] && !frame->data[1]&&!frame->data[2]){
        av_frame_free(&frame);
        //        stop();
        //        sendEndEvent();
        return;
    }

    if(vPars == nullptr){
        initVideo();
    }

    int width = frame->width;
    int height = frame->height;

    int64_t videoTime = 1000 * frame->pts * av_q2d(vPars->timeBase);
    int64_t delay = 0;
    //    std::cerr<<"video time:" << videoTime<<std::endl;
    //    std::cout<< "videoTime = " <<std::fixed<< std::setprecision(6) << videoTime << std::endl;
    //    std::cout<< "audioClock = " <<std::fixed<< std::setprecision(6) << audioClock << std::endl;
    //    std::cout<< "syncThreshold = " <<std::fixed<< std::setprecision(6) << syncThreshold << std::endl;
    //    std::cout<< "delay = " <<std::fixed<< std::setprecision(6) << delay << std::endl;

    if(speedFlag.load(std::memory_order_acquire)){
        speedFactor = speed;
        speedFlag.store(false,std::memory_order_release);
    }

    copyYUV(frame);

    QMetaObject::invokeMethod(
                renderWidget, "setYUVData",
                Qt::QueuedConnection,
                Q_ARG(uint8_t*,yBuf),
                Q_ARG(uint8_t*,uBuf),
                Q_ARG(uint8_t*,vBuf),
                Q_ARG(int,width),
                Q_ARG(int,height)
                );

    av_frame_unref(frame);
    av_frame_free(&frame);
}

int FFTimer::optimizeSync(int64_t delay, int64_t standardInterval) {
    //    if (std::abs(delay) > NOSYNC_THRESHOLD) {
    return 0;
    //    }
    //    else {
    //        double factor = 1.0;
    //        if (delay > 0) {
    //            factor = std::min(1.0 + delay / syncThreshold, MAX_INTERVAL_FACTOR);
    //        }
    //        else {
    //            double negativeFactor = std::max(0.25 * speedFactor, 1.0 + delay / syncThreshold); // 最小50%加速
    //            factor = std::max(MIN_INTERVAL_FACTOR, negativeFactor); // 防止间隔过小
    //        }

    //        // 应用安全边界并设置间隔（增加防抖动滤波）
    //        static double lastInterval = standardInterval;
    //        double newInterval = standardInterval * factor;

    //        // 滑动平均滤波（减少高频波动）
    //        newInterval = 0.8 * lastInterval + 0.2 * newInterval;

    //        setTimerInterval(newInterval);
    //        lastInterval = newInterval;

    //        if (delay < -syncThreshold * 2) {
    //            static size_t dropCount = 0;
    //            if (dropCount++ % 2 == 0) {
    //                setTimerInterval(1LL);
    //                return -1;
    //            }
    //        }
    //    }

    return 0;
}

void FFTimer::initVideo()
{
    vPars = new FFVideoPars();
    memcpy(vPars, vDecoder->getVideoPars(), sizeof(FFVideoPars));
    standardInterval = static_cast<int>(1e6 / av_q2d(vPars->frameRate));
    syncThreshold = 1000 / av_q2d(vPars->frameRate);

}

FFTimer::~FFTimer() {
    stop();
    close();
}

void FFTimer::work()
{
    std::unique_lock<std::mutex>lock(mutex);
    while (!m_stop) {
        playVideo();
        std::this_thread::sleep_for(std::chrono::milliseconds(1));
    }
}

void FFTimer::copyYUV(AVFrame *frame)
{
    yBuf = new uint8_t[frame->width * frame->height];
    uBuf = new uint8_t[frame->width * frame->height /4];
    vBuf = new uint8_t[frame->width * frame->height /4];
    for (int i = 0; i < frame->height; i++) {
        memcpy(yBuf + i * frame->width ,
               frame->data[0] + i * frame->linesize[0],
                frame->width);
    }
    for (int i = 0; i < frame->height / 2; i++) {
        memcpy(uBuf + i * frame->width / 2,
               frame->data[1] + i * frame->linesize[1],
                frame->width / 2);
        memcpy(vBuf + i *  frame->width / 2,
               frame->data[2] + i * frame->linesize[2],
                frame->width / 2);
    }

}


